home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / lib / xulrunner-1.9.1.5 / components / nsLivemarkService.js < prev    next >
Text File  |  2009-11-09  |  37KB  |  1,141 lines

  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  * ***** BEGIN LICENSE BLOCK *****
  3.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Mozilla Public License
  6.  * Version 1.1 (the "License"); you may not use this file except in
  7.  * compliance with the License. You may obtain a copy of the License
  8.  * at http://www.mozilla.org/MPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS"
  11.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  12.  * the License for the specific language governing rights and
  13.  * limitations under the License.
  14.  *
  15.  * The Original Code is the Places JS Livemark Service.
  16.  *
  17.  * The Initial Developer of the Original Code is Mozilla Corporation.
  18.  * Portions created by the Initial Developer are Copyright (C) 2006
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *   Annie Sullivan <annie.sullivan@gmail.com> (C++ author)
  23.  *   Joe Hughes <joe@retrovirus.com>
  24.  *   Vladimir Vukicevic <vladimir@pobox.com>
  25.  *   Masayuki Nakano <masayuki@d-toybox.com>
  26.  *   Robert Sayre <sayrer@gmail.com> (JS port)
  27.  *   Phil Ringnalda <philringnalda@gmail.com>
  28.  *   Marco Bonardo <mak77@bonardo.net>
  29.  *   Takeshi Ichimaru <ayakawa.m@gmail.com>
  30.  *
  31.  * Alternatively, the contents of this file may be used under the
  32.  * terms of either the GNU General Public License Version 2 or later
  33.  * (the "GPL"), or the GNU Lesser General Public License Version 2.1
  34.  * or later (the "LGPL"), in which case the provisions of the GPL or
  35.  * the LGPL are applicable instead of those above. If you wish to
  36.  * allow use of your version of this file only under the terms of
  37.  * either the GPL or the LGPL, and not to allow others to use your
  38.  * version of this file under the terms of the MPL, indicate your
  39.  * decision by deleting the provisions above and replace them with the
  40.  * notice and other provisions required by the GPL or the LGPL. If you
  41.  * do not delete the provisions above, a recipient may use your
  42.  * version of this file under the terms of any one of the MPL, the GPL
  43.  * or the LGPL.
  44.  *
  45.  * ***** END LICENSE BLOCK ***** */
  46.  
  47. const Cc = Components.classes;
  48. const Ci = Components.interfaces;
  49. const Cr = Components.results;
  50.  
  51. //@line 36 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/content/moz/lang.js"
  52.  
  53.  
  54. /**
  55.  * lang.js - Some missing JavaScript language features
  56.  */
  57.  
  58. /**
  59.  * Partially applies a function to a particular "this object" and zero or
  60.  * more arguments. The result is a new function with some arguments of the first
  61.  * function pre-filled and the value of |this| "pre-specified".
  62.  *
  63.  * Remaining arguments specified at call-time are appended to the pre-
  64.  * specified ones.
  65.  *
  66.  * Usage:
  67.  * var barMethBound = BindToObject(myFunction, myObj, "arg1", "arg2");
  68.  * barMethBound("arg3", "arg4");
  69.  *
  70.  * @param fn {string} Reference to the function to be bound
  71.  *
  72.  * @param self {object} Specifies the object which |this| should point to
  73.  * when the function is run. If the value is null or undefined, it will default
  74.  * to the global object.
  75.  *
  76.  * @returns {function} A partially-applied form of the speficied function.
  77.  */
  78. function BindToObject(fn, self, opt_args) {
  79.   var boundargs = fn.boundArgs_ || [];
  80.   boundargs = boundargs.concat(Array.slice(arguments, 2, arguments.length));
  81.  
  82.   if (fn.boundSelf_)
  83.     self = fn.boundSelf_;
  84.   if (fn.boundFn_)
  85.     fn = fn.boundFn_;
  86.  
  87.   var newfn = function() {
  88.     // Combine the static args and the new args into one big array
  89.     var args = boundargs.concat(Array.slice(arguments));
  90.     return fn.apply(self, args);
  91.   }
  92.  
  93.   newfn.boundArgs_ = boundargs;
  94.   newfn.boundSelf_ = self;
  95.   newfn.boundFn_ = fn;
  96.  
  97.   return newfn;
  98. }
  99.  
  100. /**
  101.  * Inherit the prototype methods from one constructor into another.
  102.  *
  103.  * Usage:
  104.  *
  105.  * function ParentClass(a, b) { }
  106.  * ParentClass.prototype.foo = function(a) { }
  107.  *
  108.  * function ChildClass(a, b, c) {
  109.  *   ParentClass.call(this, a, b);
  110.  * }
  111.  *
  112.  * ChildClass.inherits(ParentClass);
  113.  *
  114.  * var child = new ChildClass("a", "b", "see");
  115.  * child.foo(); // works
  116.  *
  117.  * In addition, a superclass' implementation of a method can be invoked
  118.  * as follows:
  119.  *
  120.  * ChildClass.prototype.foo = function(a) {
  121.  *   ChildClass.superClass_.foo.call(this, a);
  122.  *   // other code
  123.  * };
  124.  */
  125. Function.prototype.inherits = function(parentCtor) {
  126.   var tempCtor = function(){};
  127.   tempCtor.prototype = parentCtor.prototype;
  128.   this.superClass_ = parentCtor.prototype;
  129.   this.prototype = new tempCtor();
  130. }
  131. //@line 36 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/content/moz/observer.js"
  132.  
  133.  
  134. // A couple of classes to simplify creating observers. 
  135. //
  136. // // Example1:
  137. //
  138. // function doSomething() { ... }
  139. // var observer = new G_ObserverWrapper(topic, doSomething);
  140. // someObj.addObserver(topic, observer);
  141. //
  142. // // Example2: 
  143. //
  144. // function doSomething() { ... }
  145. // new G_ObserverServiceObserver("profile-after-change", 
  146. //                               doSomething,
  147. //                               true /* run only once */);
  148.  
  149.  
  150. /**
  151.  * This class abstracts the admittedly simple boilerplate required of
  152.  * an nsIObserver. It saves you the trouble of implementing the
  153.  * indirection of your own observe() function.
  154.  *
  155.  * @param topic String containing the topic the observer will filter for
  156.  *
  157.  * @param observeFunction Reference to the function to call when the 
  158.  *                        observer fires
  159.  *
  160.  * @constructor
  161.  */
  162. function G_ObserverWrapper(topic, observeFunction) {
  163.   this.debugZone = "observer";
  164.   this.topic_ = topic;
  165.   this.observeFunction_ = observeFunction;
  166. }
  167.  
  168. /**
  169.  * XPCOM
  170.  */
  171. G_ObserverWrapper.prototype.QueryInterface = function(iid) {
  172.   if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIObserver))
  173.     return this;
  174.   throw Components.results.NS_ERROR_NO_INTERFACE;
  175. }
  176.  
  177. /**
  178.  * Invoked by the thingy being observed
  179.  */
  180. G_ObserverWrapper.prototype.observe = function(subject, topic, data) {
  181.   if (topic == this.topic_)
  182.     this.observeFunction_(subject, topic, data);
  183. }
  184.  
  185.  
  186. /**
  187.  * This class abstracts the admittedly simple boilerplate required of
  188.  * observing an observerservice topic. It implements the indirection
  189.  * required, and automatically registers to hear the topic.
  190.  *
  191.  * @param topic String containing the topic the observer will filter for
  192.  *
  193.  * @param observeFunction Reference to the function to call when the 
  194.  *                        observer fires
  195.  *
  196.  * @param opt_onlyOnce Boolean indicating if the observer should unregister
  197.  *                     after it has fired
  198.  *
  199.  * @constructor
  200.  */
  201. function G_ObserverServiceObserver(topic, observeFunction, opt_onlyOnce) {
  202.   this.debugZone = "observerserviceobserver";
  203.   this.topic_ = topic;
  204.   this.observeFunction_ = observeFunction;
  205.   this.onlyOnce_ = !!opt_onlyOnce;
  206.   
  207.   this.observer_ = new G_ObserverWrapper(this.topic_, 
  208.                                          BindToObject(this.observe_, this));
  209.   this.observerService_ = Cc["@mozilla.org/observer-service;1"]
  210.                           .getService(Ci.nsIObserverService);
  211.   this.observerService_.addObserver(this.observer_, this.topic_, false);
  212. }
  213.  
  214. /**
  215.  * Unregister the observer from the observerservice
  216.  */
  217. G_ObserverServiceObserver.prototype.unregister = function() {
  218.   this.observerService_.removeObserver(this.observer_, this.topic_);
  219.   this.observerService_ = null;
  220. }
  221.  
  222. /**
  223.  * Invoked by the observerservice
  224.  */
  225. G_ObserverServiceObserver.prototype.observe_ = function(subject, topic, data) {
  226.   this.observeFunction_(subject, topic, data);
  227.   if (this.onlyOnce_)
  228.     this.unregister();
  229. }
  230.  
  231. //@line 36 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/content/moz/alarm.js"
  232.  
  233.  
  234. // An Alarm fires a callback after a certain amount of time, or at
  235. // regular intervals. It's a convenient replacement for
  236. // setTimeout/Interval when you don't want to bind to a specific
  237. // window.
  238. //
  239. // The ConditionalAlarm is an Alarm that cancels itself if its callback 
  240. // returns a value that type-converts to true.
  241. //
  242. // Example:
  243. //
  244. //  function foo() { dump('hi'); };
  245. //  new G_Alarm(foo, 10*1000);                   // Fire foo in 10 seconds
  246. //  new G_Alarm(foo, 10*1000, true /*repeat*/);  // Fire foo every 10 seconds
  247. //  new G_Alarm(foo, 10*1000, true, 7);          // Fire foo every 10 seconds
  248. //                                               // seven times
  249. //  new G_ConditionalAlarm(foo, 1000, true); // Fire every sec until foo()==true
  250. //
  251. //  // Fire foo every 10 seconds until foo returns true or until it fires seven
  252. //  // times, whichever happens first.
  253. //  new G_ConditionalAlarm(foo, 10*1000, true /*repeating*/, 7);
  254. //
  255. // TODO: maybe pass an isFinal flag to the callback if they opted to
  256. // set maxTimes and this is the last iteration?
  257.  
  258.  
  259. /**
  260.  * Set an alarm to fire after a given amount of time, or at specific 
  261.  * intervals.
  262.  *
  263.  * @param callback Function to call when the alarm fires
  264.  * @param delayMS Number indicating the length of the alarm period in ms
  265.  * @param opt_repeating Boolean indicating whether this should fire 
  266.  *                      periodically
  267.  * @param opt_maxTimes Number indicating a maximum number of times to 
  268.  *                     repeat (obviously only useful when opt_repeating==true)
  269.  */
  270. function G_Alarm(callback, delayMS, opt_repeating, opt_maxTimes) {
  271.   this.debugZone = "alarm";
  272.   this.callback_ = callback;
  273.   this.repeating_ = !!opt_repeating;
  274.   this.timer_ = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  275.   var type = opt_repeating ? 
  276.              this.timer_.TYPE_REPEATING_SLACK : 
  277.              this.timer_.TYPE_ONE_SHOT;
  278.   this.maxTimes_ = opt_maxTimes ? opt_maxTimes : null;
  279.   this.nTimes_ = 0;
  280.  
  281.   this.observerServiceObserver_ = new G_ObserverServiceObserver(
  282.                                         'xpcom-shutdown',
  283.                                         BindToObject(this.cancel, this));
  284.  
  285.   // Ask the timer to use nsITimerCallback (.notify()) when ready
  286.   this.timer_.initWithCallback(this, delayMS, type);
  287. }
  288.  
  289. /**
  290.  * Cancel this timer 
  291.  */
  292. G_Alarm.prototype.cancel = function() {
  293.   if (!this.timer_) {
  294.     return;
  295.   }
  296.  
  297.   this.timer_.cancel();
  298.   // Break circular reference created between this.timer_ and the G_Alarm
  299.   // instance (this)
  300.   this.timer_ = null;
  301.   this.callback_ = null;
  302.  
  303.   // We don't need the shutdown observer anymore
  304.   this.observerServiceObserver_.unregister();
  305. }
  306.  
  307. /**
  308.  * Invoked by the timer when it fires
  309.  * 
  310.  * @param timer Reference to the nsITimer which fired (not currently 
  311.  *              passed along)
  312.  */
  313. G_Alarm.prototype.notify = function(timer) {
  314.   // fire callback and save results
  315.   var ret = this.callback_();
  316.   
  317.   // If they've given us a max number of times to fire, enforce it
  318.   this.nTimes_++;
  319.   if (this.repeating_ && 
  320.       typeof this.maxTimes_ == "number" 
  321.       && this.nTimes_ >= this.maxTimes_) {
  322.     this.cancel();
  323.   } else if (!this.repeating_) {
  324.     // Clear out the callback closure for TYPE_ONE_SHOT timers
  325.     this.cancel();
  326.   }
  327.   // We don't cancel/cleanup timers that repeat forever until either
  328.   // xpcom-shutdown occurs or cancel() is called explicitly.
  329.  
  330.   return ret;
  331. }
  332.  
  333. G_Alarm.prototype.setDelay = function(delay) {
  334.   this.timer_.delay = delay;
  335. }
  336.  
  337. /**
  338.  * XPCOM cruft
  339.  */
  340. G_Alarm.prototype.QueryInterface = function(iid) {
  341.   if (iid.equals(Components.interfaces.nsISupports) ||
  342.       iid.equals(Components.interfaces.nsITimerCallback))
  343.     return this;
  344.  
  345.   throw Components.results.NS_ERROR_NO_INTERFACE;
  346. }
  347.  
  348.  
  349. /**
  350.  * An alarm with the additional property that it cancels itself if its 
  351.  * callback returns true.
  352.  *
  353.  * For parameter documentation, see G_Alarm
  354.  */
  355. function G_ConditionalAlarm(callback, delayMS, opt_repeating, opt_maxTimes) {
  356.   G_Alarm.call(this, callback, delayMS, opt_repeating, opt_maxTimes);
  357.   this.debugZone = "conditionalalarm";
  358. }
  359.  
  360. G_ConditionalAlarm.inherits(G_Alarm);
  361.  
  362. /**
  363.  * Invoked by the timer when it fires
  364.  * 
  365.  * @param timer Reference to the nsITimer which fired (not currently 
  366.  *              passed along)
  367.  */
  368. G_ConditionalAlarm.prototype.notify = function(timer) {
  369.   // Call G_Alarm::notify
  370.   var rv = G_Alarm.prototype.notify.call(this, timer);
  371.  
  372.   if (this.repeating_ && rv) {
  373.     G_Debug(this, "Callback of a repeating alarm returned true; cancelling.");
  374.     this.cancel();
  375.   }
  376. }
  377. //@line 54 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/places/src/nsLivemarkService.js"
  378.  
  379. const LS_CLASSID = Components.ID("{dca61eb5-c7cd-4df1-b0fb-d0722baba251}");
  380. const LS_CLASSNAME = "Livemark Service";
  381. const LS_CONTRACTID = "@mozilla.org/browser/livemark-service;2";
  382.  
  383. const LMANNO_FEEDURI = "livemark/feedURI";
  384. const LMANNO_SITEURI = "livemark/siteURI";
  385. const LMANNO_EXPIRATION = "livemark/expiration";
  386. const LMANNO_LOADFAILED = "livemark/loadfailed";
  387. const LMANNO_LOADING = "livemark/loading";
  388.  
  389. const PS_CONTRACTID = "@mozilla.org/preferences-service;1";
  390. const NH_CONTRACTID = "@mozilla.org/browser/nav-history-service;1";
  391. const AS_CONTRACTID = "@mozilla.org/browser/annotation-service;1";
  392. const OS_CONTRACTID = "@mozilla.org/observer-service;1";
  393. const SB_CONTRACTID = "@mozilla.org/intl/stringbundle;1";
  394. const IO_CONTRACTID = "@mozilla.org/network/io-service;1";
  395. const BMS_CONTRACTID = "@mozilla.org/browser/nav-bookmarks-service;1";
  396. const FAV_CONTRACTID = "@mozilla.org/browser/favicon-service;1";
  397. const LG_CONTRACTID = "@mozilla.org/network/load-group;1";
  398. const FP_CONTRACTID = "@mozilla.org/feed-processor;1";
  399. const SEC_CONTRACTID = "@mozilla.org/scriptsecuritymanager;1";
  400. const IS_CONTRACTID = "@mozilla.org/widget/idleservice;1";
  401. const SEC_FLAGS = Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL;
  402.  
  403. // Expire livemarks after 1 hour by default
  404. var gExpiration = 3600000;
  405.  
  406. // Number of livemarks that are read at once
  407. var gLimitCount = 1;
  408.  
  409. // Interval when livemarks are loaded
  410. var gDelayTime  = 3;
  411.  
  412. // Expire livemarks after 10 minutes on error
  413. const ERROR_EXPIRATION = 600000;
  414.  
  415. // Don't check when the user is idle for longer than half an hour
  416. const IDLE_TIMELIMIT = 1800000;
  417.  
  418. // We should check for expiration _at least_ every hour
  419. // This cap is used only if the user sets a very high expiration time (>4h)
  420. const MAX_REFRESH_TIME = 3600000;
  421.  
  422. /* We don't have strings, so this is currently not used.
  423. const PLACES_BUNDLE_URI = "chrome://places/locale/places.properties";
  424.  
  425. function LOG(str) {
  426.   dump("*** " + str + "\n");
  427. }
  428.  
  429. var gStringBundle;
  430. function GetString(name)
  431. {
  432.   try {
  433.     if (!gStringBundle) {
  434.       var bundleService = Cc[SB_CONTRACTID].getService();
  435.       bundleService = bundleService.QueryInterface(Ci.nsIStringBundleService);
  436.       gStringBundle = bundleService.createBundle(PLACES_BUNDLE_URI);
  437.     }
  438.  
  439.     if (gStringBundle)
  440.       return gStringBundle.GetStringFromName(name);
  441.   } catch (ex) {
  442.     LOG("Exception loading string bundle: " + ex.message);
  443.   }
  444.  
  445.   return null;
  446. }
  447. */
  448.  
  449. function MarkLivemarkLoadFailed(aFolderId) {
  450.   var ans = Cc[AS_CONTRACTID].getService(Ci.nsIAnnotationService);
  451.   // if it failed before, nothing more to do
  452.   if (ans.itemHasAnnotation(aFolderId, LMANNO_LOADFAILED))
  453.     return;
  454.  
  455.   // removeItemAnnotation can safely be used even when the anno isn't set
  456.   ans.removeItemAnnotation(aFolderId, LMANNO_LOADING);
  457.   ans.setItemAnnotation(aFolderId, LMANNO_LOADFAILED, true,
  458.                         0, ans.EXPIRE_NEVER);
  459. }
  460.  
  461. function LivemarkService() {
  462.  
  463.   try {
  464.     var prefs = Cc[PS_CONTRACTID].getService(Ci.nsIPrefBranch);
  465.     var livemarkRefresh =
  466.       prefs.getIntPref("browser.bookmarks.livemark_refresh_seconds");
  467.     // Reset global expiration variable to reflect hidden pref (in ms)
  468.     // with a lower limit of 1 minute (60000 ms)
  469.     gExpiration = Math.max(livemarkRefresh * 1000, 60000);
  470.   }
  471.   catch (ex) { }
  472.  
  473.   try {
  474.     gLimitCount = prefs.getIntPref("browser.bookmarks.livemark_refresh_limit_count");
  475.     if ( gLimitCount < 1 ) gLimitCount = 1;
  476.   }
  477.   catch (ex) { }
  478.  
  479.   try {
  480.     gDelayTime = prefs.getIntPref("browser.bookmarks.livemark_refresh_delay_time");
  481.     if ( gDelayTime < 1 ) gDelayTime = 1;
  482.   }
  483.   catch (ex) { }
  484.  
  485.   // [ {folderId:, folderURI:, feedURI:, loadGroup:, locked: } ];
  486.   this._livemarks = [];
  487.  
  488.   this._observerServiceObserver =
  489.     new G_ObserverServiceObserver('xpcom-shutdown',
  490.                                   BindToObject(this._shutdown, this),
  491.                                   true /*only once*/);
  492.  
  493.   var livemarks = this._ans.getItemsWithAnnotation(LMANNO_FEEDURI, {});
  494.   for (var i = 0; i < livemarks.length; i++) {
  495.     var feedURI = this._ios.newURI(this._ans.getItemAnnotation(livemarks[i],
  496.                                                                LMANNO_FEEDURI),
  497.                                    null, null);
  498.     this._pushLivemark(livemarks[i], feedURI);
  499.   }
  500.  
  501.   this._bms.addObserver(this, false);
  502. }
  503.  
  504. LivemarkService.prototype = {
  505.  
  506.   get _bms() {
  507.     if (!this.__bms)
  508.       this.__bms = Cc[BMS_CONTRACTID].getService(Ci.nsINavBookmarksService);
  509.     return this.__bms;
  510.   },
  511.  
  512.   get _history() {
  513.     if (!this.__history)
  514.       this.__history = Cc[NH_CONTRACTID].getService(Ci.nsINavHistoryService);
  515.     return this.__history;
  516.   },
  517.  
  518.   get _ans() {
  519.     if (!this.__ans)
  520.       this.__ans = Cc[AS_CONTRACTID].getService(Ci.nsIAnnotationService);
  521.     return this.__ans;
  522.   },
  523.  
  524.   get _ios() {
  525.     if (!this.__ios)
  526.       this.__ios = Cc[IO_CONTRACTID].getService(Ci.nsIIOService);
  527.     return this.__ios;
  528.   },
  529.  
  530.   get _idleService() {
  531.   if (!(IS_CONTRACTID in Cc))
  532.     return null;
  533.   if (!this.__idleService)
  534.     this.__idleService = Cc[IS_CONTRACTID].getService(Ci.nsIIdleService);
  535.   return this.__idleService;
  536.   },
  537.  
  538.   _updateTimer: null,
  539.   start: function LS_start() {
  540.     if (this._updateTimer)
  541.       return;
  542.     // start is called in delayed startup, 5s after browser startup
  543.     // we do a first check of the livemarks here, next checks will be on timer
  544.     // browser start => 5s => this.start() => check => refresh_time => check
  545.     this._checkAllLivemarks();
  546.   },
  547.  
  548.   stopUpdateLivemarks: function LS_stopUpdateLivemarks() {
  549.     for (var livemark in this._livemarks) {
  550.       if (livemark.loadGroup)
  551.         livemark.loadGroup.cancel(Components.results.NS_BINDING_ABORTED);
  552.     }
  553.     // kill timer
  554.     if (this._updateTimer) {
  555.       this._updateTimer.cancel();
  556.       this._updateTimer = null;
  557.     }
  558.   },
  559.  
  560.   _pushLivemark: function LS__pushLivemark(aFolderId, aFeedURI) {
  561.     // returns new length of _livemarks
  562.     return this._livemarks.push({folderId: aFolderId, feedURI: aFeedURI});
  563.   },
  564.  
  565.   _getLivemarkIndex: function LS__getLivemarkIndex(aFolderId) {
  566.     for (var i = 0; i < this._livemarks.length; ++i) {
  567.       if (this._livemarks[i].folderId == aFolderId)
  568.         return i;
  569.     }
  570.     throw Cr.NS_ERROR_INVALID_ARG;
  571.   },
  572.  
  573.   _shutdown: function LS__shutdown() {
  574.     // remove bookmarks observer
  575.     this._bms.removeObserver(this);
  576.  
  577.     // stop to update livemarks
  578.     this.stopUpdateLivemarks();
  579.   },
  580.  
  581.   // We try to distribute the load of the livemark update.
  582.   // load gLimitCount Livemarks per gDelayTime sec.
  583.   _nextUpdateStartIndex : 0,
  584.   _checkAllLivemarks: function LS__checkAllLivemarks() {
  585.     var startNo = this._nextUpdateStartIndex;
  586.     var count = 0;
  587.     for (var i = startNo; (i < this._livemarks.length) && (count < gLimitCount); ++i ) {
  588.       // check if livemarks are expired, update if needed
  589.       try {
  590.         if (this._updateLivemarkChildren(i, false)) count++;
  591.       }
  592.       catch (ex) { }
  593.       this._nextUpdateStartIndex = i+1;
  594.     }
  595.     if ( this._nextUpdateStartIndex >= this._livemarks.length ) {
  596.       // all livemarks are checked, sleeping until next period
  597.       this._nextUpdateStartIndex = 0;
  598.       var refresh_time = Math.min(Math.floor(gExpiration / 4), MAX_REFRESH_TIME);
  599.       this._updateTimer = new G_Alarm(BindToObject(this._checkAllLivemarks, this),
  600.                                       refresh_time);
  601.     } else {
  602.       // wait gDelayTime sec.
  603.       this._updateTimer = new G_Alarm(BindToObject(this._checkAllLivemarks, this),
  604.                                       gDelayTime*1000);
  605.     }
  606.   },
  607.  
  608.   deleteLivemarkChildren: function LS_deleteLivemarkChildren(aFolderId) {
  609.     this._bms.removeFolderChildren(aFolderId);
  610.   },
  611.  
  612.   _updateLivemarkChildren:
  613.   function LS__updateLivemarkChildren(aIndex, aForceUpdate) {
  614.     if (this._livemarks[aIndex].locked)
  615.       return false;
  616.  
  617.     var livemark = this._livemarks[aIndex];
  618.     livemark.locked = true;
  619.     try {
  620.       // Check the TTL/expiration on this.  If there isn't one,
  621.       // then we assume it's never been loaded.  We perform this
  622.       // check even when the update is being forced, in case the
  623.       // livemark has somehow never been loaded.
  624.       var expireTime = this._ans.getItemAnnotation(livemark.folderId,
  625.                                                    LMANNO_EXPIRATION);
  626.       if (!aForceUpdate && expireTime > Date.now()) {
  627.         // no need to refresh
  628.         livemark.locked = false;
  629.         return false;
  630.       }
  631.  
  632.       // Check the user idle time.
  633.       // If the user is away from the computer, don't bother updating,
  634.       // so we save some bandwidth. 
  635.       // If we can't get the idle time, assume the user is not idle.
  636.       var idleTime = 0;
  637.       try {
  638.         idleTime = this._idleService.idleTime;
  639.       }
  640.       catch (ex) { /* We don't care */ }
  641.       if (idleTime > IDLE_TIMELIMIT) {
  642.         livemark.locked = false;
  643.         return false;
  644.       }
  645.     }
  646.     catch (ex) {
  647.       // This livemark has never been loaded, since it has no expire time.
  648.     }
  649.  
  650.     var loadgroup;
  651.     try {
  652.       // Create a load group for the request.  This will allow us to
  653.       // automatically keep track of redirects, so we can always
  654.       // cancel the channel.
  655.       loadgroup = Cc[LG_CONTRACTID].createInstance(Ci.nsILoadGroup);
  656.       var uriChannel = this._ios.newChannel(livemark.feedURI.spec, null, null);
  657.       uriChannel.loadGroup = loadgroup;
  658.       uriChannel.loadFlags |= Ci.nsIRequest.LOAD_BACKGROUND |
  659.                               Ci.nsIRequest.VALIDATE_ALWAYS;
  660.       var httpChannel = uriChannel.QueryInterface(Ci.nsIHttpChannel);
  661.       httpChannel.requestMethod = "GET";
  662.       httpChannel.setRequestHeader("X-Moz", "livebookmarks", false);
  663.  
  664.       // Stream the result to the feed parser with this listener
  665.       var listener = new LivemarkLoadListener(livemark);
  666.       // removeItemAnnotation can safely be used even when the anno isn't set
  667.       this._ans.removeItemAnnotation(livemark.folderId, LMANNO_LOADFAILED);
  668.       this._ans.setItemAnnotation(livemark.folderId, LMANNO_LOADING, true,
  669.                                   0, this._ans.EXPIRE_NEVER);
  670.       httpChannel.notificationCallbacks = listener;
  671.       httpChannel.asyncOpen(listener, null);
  672.     }
  673.     catch (ex) {
  674.       MarkLivemarkLoadFailed(livemark.folderId);
  675.       livemark.locked = false;
  676.       return false;
  677.     }
  678.     livemark.loadGroup = loadgroup;
  679.     return true;
  680.   },
  681.  
  682.   createLivemark: function LS_createLivemark(aParentId, aName, aSiteURI,
  683.                                              aFeedURI, aIndex) {
  684.     if (!aParentId || !aFeedURI)
  685.       throw Cr.NS_ERROR_INVALID_ARG;
  686.  
  687.     // Don't add livemarks to livemarks
  688.     if (this.isLivemark(aParentId))
  689.       throw Cr.NS_ERROR_INVALID_ARG;
  690.  
  691.     var folderId = this._createFolder(aParentId, aName, aSiteURI,
  692.                                       aFeedURI, aIndex);
  693.  
  694.     // do a first update of the livemark children
  695.     this._updateLivemarkChildren(this._pushLivemark(folderId, aFeedURI) - 1,
  696.                                  false);
  697.  
  698.     return folderId;
  699.   },
  700.  
  701.   createLivemarkFolderOnly:
  702.   function LS_createLivemarkFolderOnly(aParentId, aName, aSiteURI,
  703.                                        aFeedURI, aIndex) {
  704.     if (aParentId < 1 || !aFeedURI)
  705.       throw Cr.NS_ERROR_INVALID_ARG;
  706.  
  707.     // Don't add livemarks to livemarks
  708.     if (this.isLivemark(aParentId))
  709.       throw Cr.NS_ERROR_INVALID_ARG;
  710.  
  711.     var folderId = this._createFolder(aParentId, aName, aSiteURI,
  712.                                       aFeedURI, aIndex);
  713.  
  714.     var livemarkIndex = this._pushLivemark(folderId, aFeedURI) - 1;
  715.     var livemark = this._livemarks[livemarkIndex];
  716.     return folderId;
  717.   },
  718.  
  719.   _createFolder:
  720.   function LS__createFolder(aParentId, aName, aSiteURI, aFeedURI, aIndex) {
  721.     var folderId = this._bms.createFolder(aParentId, aName, aIndex);
  722.     this._bms.setFolderReadonly(folderId, true);
  723.  
  724.     // Add an annotation to map the folder id to the livemark feed URI
  725.     this._ans.setItemAnnotation(folderId, LMANNO_FEEDURI, aFeedURI.spec,
  726.                                 0, this._ans.EXPIRE_NEVER);
  727.  
  728.     if (aSiteURI) {
  729.       // Add an annotation to map the folder URI to the livemark site URI
  730.       this._setSiteURISecure(folderId, aFeedURI, aSiteURI);
  731.     }
  732.  
  733.     return folderId;
  734.   },
  735.  
  736.   isLivemark: function LS_isLivemark(aFolderId) {
  737.     if (aFolderId < 1)
  738.       throw Cr.NS_ERROR_INVALID_ARG;
  739.     return this._ans.itemHasAnnotation(aFolderId, LMANNO_FEEDURI);
  740.   },
  741.  
  742.   _ensureLivemark: function LS__ensureLivemark(aFolderId) {
  743.     if (!this.isLivemark(aFolderId))
  744.       throw Cr.NS_ERROR_INVALID_ARG;
  745.   },
  746.  
  747.   getSiteURI: function LS_getSiteURI(aFolderId) {
  748.     this._ensureLivemark(aFolderId);
  749.  
  750.     if (this._ans.itemHasAnnotation(aFolderId, LMANNO_SITEURI)) {
  751.       var siteURIString =
  752.         this._ans.getItemAnnotation(aFolderId, LMANNO_SITEURI);
  753.  
  754.       return this._ios.newURI(siteURIString, null, null);
  755.     }
  756.     return null;
  757.   },
  758.  
  759.   setSiteURI: function LS_setSiteURI(aFolderId, aSiteURI) {
  760.     this._ensureLivemark(aFolderId);
  761.  
  762.     if (!aSiteURI) {
  763.       this._ans.removeItemAnnotation(aFolderId, LMANNO_SITEURI);
  764.       return;
  765.     }
  766.  
  767.     var livemarkIndex = this._getLivemarkIndex(aFolderId);
  768.     var livemark = this._livemarks[livemarkIndex];
  769.     this._setSiteURISecure(aFolderId, livemark.feedURI, aSiteURI);
  770.   },
  771.  
  772.   _setSiteURISecure:
  773.   function LS__setSiteURISecure(aFolderId, aFeedURI, aSiteURI) {
  774.     var secMan = Cc[SEC_CONTRACTID].getService(Ci.nsIScriptSecurityManager);
  775.     var feedPrincipal = secMan.getCodebasePrincipal(aFeedURI);
  776.     try {
  777.       secMan.checkLoadURIWithPrincipal(feedPrincipal, aSiteURI, SEC_FLAGS);
  778.     }
  779.     catch (e) {
  780.       return;
  781.     }
  782.     this._ans.setItemAnnotation(aFolderId, LMANNO_SITEURI, aSiteURI.spec,
  783.                                 0, this._ans.EXPIRE_NEVER);
  784.   },
  785.  
  786.   getFeedURI: function LS_getFeedURI(aFolderId) {
  787.     if (this._ans.itemHasAnnotation(aFolderId, LMANNO_FEEDURI))
  788.       return this._ios.newURI(this._ans.getItemAnnotation(aFolderId,
  789.                                                           LMANNO_FEEDURI),
  790.                               null, null);
  791.     return null;
  792.   },
  793.  
  794.   setFeedURI: function LS_setFeedURI(aFolderId, aFeedURI) {
  795.     if (!aFeedURI)
  796.       throw Cr.NS_ERROR_INVALID_ARG;
  797.  
  798.     this._ans.setItemAnnotation(aFolderId, LMANNO_FEEDURI, aFeedURI.spec, 0,
  799.                                 this._ans.EXPIRE_NEVER);
  800.  
  801.     // now update our internal table
  802.     var livemarkIndex = this._getLivemarkIndex(aFolderId);
  803.     this._livemarks[livemarkIndex].feedURI = aFeedURI;
  804.   },
  805.  
  806.   reloadAllLivemarks: function LS_reloadAllLivemarks() {
  807.     for (var i = 0; i < this._livemarks.length; ++i) {
  808.       this._updateLivemarkChildren(i, true);
  809.     }
  810.   },
  811.  
  812.   reloadLivemarkFolder: function LS_reloadLivemarkFolder(aFolderId) {
  813.     var livemarkIndex = this._getLivemarkIndex(aFolderId);
  814.     this._updateLivemarkChildren(livemarkIndex, true);
  815.   },
  816.  
  817.   // nsINavBookmarkObserver
  818.   onBeginUpdateBatch: function() { },
  819.   onEndUpdateBatch: function() { },
  820.   onItemAdded: function() { },
  821.   onItemChanged: function() { },
  822.   onItemVisited: function() { },
  823.   onItemMoved: function() { },
  824.  
  825.   onItemRemoved: function(aItemId, aParentId, aIndex) {
  826.     // we don't need to remove annotations since itemAnnotations
  827.     // are already removed with the bookmark
  828.     try {
  829.       var livemarkIndex = this._getLivemarkIndex(aItemId);
  830.     }
  831.     catch(ex) {
  832.       // not a livemark
  833.       return;
  834.     }
  835.     var livemark = this._livemarks[livemarkIndex];
  836.  
  837.     // remove the livemark from the update array
  838.     this._livemarks.splice(livemarkIndex, 1);
  839.  
  840.     if (livemark.loadGroup)
  841.       livemark.loadGroup.cancel(Components.results.NS_BINDING_ABORTED);
  842.   },
  843.  
  844.   createInstance: function LS_createInstance(aOuter, aIID) {
  845.     if (aOuter != null)
  846.       throw Cr.NS_ERROR_NO_AGGREGATION;
  847.     return this.QueryInterface(aIID);
  848.   },
  849.  
  850.   QueryInterface: function LS_QueryInterface(aIID) {
  851.     if (aIID.equals(Ci.nsILivemarkService) ||
  852.         aIID.equals(Ci.nsIFactory) ||
  853.         aIID.equals(Ci.nsINavBookmarkObserver) ||
  854.         aIID.equals(Ci.nsISupports))
  855.       return this;
  856.     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  857.   }
  858. };
  859.  
  860. function LivemarkLoadListener(aLivemark) {
  861.   this._livemark = aLivemark;
  862.   this._processor = null;
  863.   this._isAborted = false;
  864.   this._ttl = gExpiration;
  865. }
  866.  
  867. LivemarkLoadListener.prototype = {
  868.  
  869.   abort: function LLL_abort() {
  870.     this._isAborted = true;
  871.   },
  872.  
  873.   get _bms() {
  874.     if (!this.__bms)
  875.       this.__bms = Cc[BMS_CONTRACTID].getService(Ci.nsINavBookmarksService);
  876.     return this.__bms;
  877.   },
  878.  
  879.   get _history() {
  880.     if (!this.__history)
  881.       this.__history = Cc[NH_CONTRACTID].getService(Ci.nsINavHistoryService);
  882.     return this.__history;
  883.   },
  884.  
  885.   get _ans() {
  886.     if (!this.__ans)
  887.       this.__ans = Cc[AS_CONTRACTID].getService(Ci.nsIAnnotationService);
  888.     return this.__ans;
  889.   },
  890.  
  891.   // called back from handleResult
  892.   runBatched: function LLL_runBatched(aUserData) {
  893.     var result = aUserData.QueryInterface(Ci.nsIFeedResult);
  894.  
  895.     // We need this to make sure the item links are safe
  896.     var secMan = Cc[SEC_CONTRACTID].getService(Ci.nsIScriptSecurityManager);
  897.     var feedPrincipal = secMan.getCodebasePrincipal(this._livemark.feedURI);
  898.  
  899.     var lmService = Cc[LS_CONTRACTID].getService(Ci.nsILivemarkService);
  900.  
  901.     // Enforce well-formedness because the existing code does
  902.     if (!result || !result.doc || result.bozo) {
  903.       MarkLivemarkLoadFailed(this._livemark.folderId);
  904.       this._ttl = gExpiration;
  905.       throw Cr.NS_ERROR_FAILURE;
  906.     }
  907.  
  908.     // Clear out any child nodes of the livemark folder, since
  909.     // they're about to be replaced.
  910.     this.deleteLivemarkChildren(this._livemark.folderId);
  911.     var feed = result.doc.QueryInterface(Ci.nsIFeed);
  912.     if (feed.link) {
  913.       var oldSiteURI = lmService.getSiteURI(this._livemark.folderId);
  914.       if (!oldSiteURI || !feed.link.equals(oldSiteURI))
  915.         lmService.setSiteURI(this._livemark.folderId, feed.link);
  916.     }
  917.     // Loop through and check for a link and a title
  918.     // as the old code did
  919.     for (var i = 0; i < feed.items.length; ++i) {
  920.       let entry = feed.items.queryElementAt(i, Ci.nsIFeedEntry);
  921.       let href = entry.link;
  922.       if (!href)
  923.         continue;
  924.  
  925.       let title = entry.title ? entry.title.plainText() : "";
  926.  
  927.       try {
  928.         secMan.checkLoadURIWithPrincipal(feedPrincipal, href, SEC_FLAGS);
  929.       }
  930.       catch(ex) {
  931.         continue;
  932.       }
  933.  
  934.       this.insertLivemarkChild(this._livemark.folderId, href, title);
  935.     }
  936.   },
  937.  
  938.   /**
  939.    * See nsIFeedResultListener.idl
  940.    */
  941.   handleResult: function LLL_handleResult(aResult) {
  942.     if (this._isAborted) {
  943.       MarkLivemarkLoadFailed(this._livemark.folderId);
  944.       this._livemark.locked = false;
  945.       return;
  946.     }
  947.     try {
  948.       // The actual work is done in runBatched, see above.
  949.       this._bms.runInBatchMode(this, aResult);
  950.     }
  951.     finally {
  952.       this._processor.listener = null;
  953.       this._processor = null;
  954.       this._livemark.locked = false;
  955.       this._ans.removeItemAnnotation(this._livemark.folderId, LMANNO_LOADING);
  956.     }
  957.   },
  958.  
  959.   deleteLivemarkChildren: LivemarkService.prototype.deleteLivemarkChildren,
  960.  
  961.   insertLivemarkChild:
  962.   function LS_insertLivemarkChild(aFolderId, aUri, aTitle) {
  963.     this._bms.insertBookmark(aFolderId, aUri, this._bms.DEFAULT_INDEX, aTitle);
  964.   },
  965.  
  966.   /**
  967.    * See nsIStreamListener.idl
  968.    */
  969.   onDataAvailable: function LLL_onDataAvailable(aRequest, aContext, aInputStream,
  970.                                                 aSourceOffset, aCount) {
  971.     if (this._processor)
  972.       this._processor.onDataAvailable(aRequest, aContext, aInputStream,
  973.                                       aSourceOffset, aCount);
  974.   },
  975.  
  976.   /**
  977.    * See nsIRequestObserver.idl
  978.    */
  979.   onStartRequest: function LLL_onStartRequest(aRequest, aContext) {
  980.     if (this._isAborted)
  981.       throw Cr.NS_ERROR_UNEXPECTED;
  982.  
  983.     var channel = aRequest.QueryInterface(Ci.nsIChannel);
  984.  
  985.     // Parse feed data as it comes in
  986.     this._processor = Cc[FP_CONTRACTID].createInstance(Ci.nsIFeedProcessor);
  987.     this._processor.listener = this;
  988.     this._processor.parseAsync(null, channel.URI);
  989.  
  990.     this._processor.onStartRequest(aRequest, aContext);
  991.   },
  992.  
  993.   /**
  994.    * See nsIRequestObserver.idl
  995.    */
  996.   onStopRequest: function LLL_onStopRequest(aRequest, aContext, aStatus) {
  997.     if (!Components.isSuccessCode(aStatus)) {
  998.       // Something went wrong, try to load again in a bit
  999.       this._setResourceTTL(ERROR_EXPIRATION);
  1000.       this._isAborted = true;
  1001.       MarkLivemarkLoadFailed(this._livemark.folderId);
  1002.       this._livemark.locked = false;
  1003.       return;
  1004.     }
  1005.     // Set an expiration on the livemark, for reloading the data
  1006.     try {
  1007.       if (this._processor)
  1008.         this._processor.onStopRequest(aRequest, aContext, aStatus);
  1009.  
  1010.       // Calculate a new ttl
  1011.       var channel = aRequest.QueryInterface(Ci.nsICachingChannel);
  1012.       if (channel) {
  1013.         var entryInfo = channel.cacheToken.QueryInterface(Ci.nsICacheEntryInfo);
  1014.         if (entryInfo) {
  1015.           // nsICacheEntryInfo returns value as seconds,
  1016.           // expireTime stores as milliseconds
  1017.           var expireTime = entryInfo.expirationTime * 1000;
  1018.           var nowTime = Date.now();
  1019.  
  1020.           // note, expireTime can be 0, see bug 383538
  1021.           if (expireTime > nowTime) {
  1022.             this._setResourceTTL(Math.max((expireTime - nowTime),
  1023.                                  gExpiration));
  1024.             return;
  1025.           }
  1026.         }
  1027.       }
  1028.     }
  1029.     catch (ex) { }
  1030.     this._setResourceTTL(this._ttl);
  1031.   },
  1032.  
  1033.   _setResourceTTL: function LLL__setResourceTTL(aMilliseconds) {
  1034.     var expireTime = Date.now() + aMilliseconds;
  1035.     this._ans.setItemAnnotation(this._livemark.folderId, LMANNO_EXPIRATION,
  1036.                                 expireTime, 0,
  1037.                                 Ci.nsIAnnotationService.EXPIRE_NEVER);
  1038.   },
  1039.  
  1040.   /**
  1041.    * See nsIBadCertListener2
  1042.    */
  1043.   notifyCertProblem: function LLL_certProblem(aSocketInfo, aStatus, aTargetSite) {
  1044.     return true;
  1045.   },
  1046.  
  1047.   /**
  1048.    * See nsISSLErrorListener
  1049.    */
  1050.   notifySSLError: function LLL_SSLError(aSocketInfo, aError, aTargetSite) {
  1051.     return true;
  1052.   },
  1053.  
  1054.   /**
  1055.    * See nsIInterfaceRequestor
  1056.    */
  1057.   getInterface: function LLL_getInterface(aIID) {
  1058.     return this.QueryInterface(aIID);
  1059.   },
  1060.  
  1061.   /**
  1062.    * See nsISupports.idl
  1063.    */
  1064.   QueryInterface: function LLL_QueryInterface(aIID) {
  1065.     if (aIID.equals(Ci.nsIFeedResultListener) ||
  1066.         aIID.equals(Ci.nsIStreamListener) ||
  1067.         aIID.equals(Ci.nsIRequestObserver)||
  1068.         aIID.equals(Ci.nsINavHistoryBatchCallback) ||
  1069.         aIID.equals(Ci.nsIBadCertListener2) ||
  1070.         aIID.equals(Ci.nsISSLErrorListener) ||
  1071.         aIID.equals(Ci.nsIInterfaceRequestor) ||
  1072.         aIID.equals(Ci.nsISupports))
  1073.       return this;
  1074.     throw Cr.NS_ERROR_NO_INTERFACE;
  1075.   },
  1076. }
  1077.  
  1078. function GenericComponentFactory(aCtor) {
  1079.   this._ctor = aCtor;
  1080. }
  1081.  
  1082. GenericComponentFactory.prototype = {
  1083.  
  1084.   _ctor: null,
  1085.  
  1086.   // nsIFactory
  1087.   createInstance: function(aOuter, aIID) {
  1088.     if (aOuter != null)
  1089.       throw Cr.NS_ERROR_NO_AGGREGATION;
  1090.     return (new this._ctor()).QueryInterface(aIID);
  1091.   },
  1092.  
  1093.   // nsISupports
  1094.   QueryInterface: function(aIID) {
  1095.     if (aIID.equals(Ci.nsIFactory) ||
  1096.         aIID.equals(Ci.nsISupports))
  1097.       return this;
  1098.     throw Cr.NS_ERROR_NO_INTERFACE;
  1099.   },
  1100.  
  1101. };
  1102.  
  1103. var Module = {
  1104.   QueryInterface: function(aIID) {
  1105.     if (aIID.equals(Ci.nsIModule) ||
  1106.         aIID.equals(Ci.nsISupports))
  1107.       return this;
  1108.  
  1109.     throw Cr.NS_ERROR_NO_INTERFACE;
  1110.   },
  1111.  
  1112.   getClassObject: function M_getClassObject(aCompMgr, aCID, aIID) {
  1113.     if (!aIID.equals(Ci.nsIFactory))
  1114.       throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  1115.     if (aCID.equals(LS_CLASSID))
  1116.       return new GenericComponentFactory(LivemarkService);
  1117.  
  1118.     throw Cr.NS_ERROR_NO_INTERFACE;
  1119.   },
  1120.  
  1121.   registerSelf: function(aCompMgr, aFile, aLocation, aType) {
  1122.     var cr = aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
  1123.  
  1124.     cr.registerFactoryLocation(LS_CLASSID, LS_CLASSNAME,
  1125.       LS_CONTRACTID, aFile, aLocation, aType);
  1126.   },
  1127.  
  1128.   unregisterSelf: function M_unregisterSelf(aCompMgr, aLocation, aType) {
  1129.     var cr = aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
  1130.     cr.unregisterFactoryLocation(LS_CLASSID, aLocation);
  1131.   },
  1132.  
  1133.   canUnload: function M_canUnload(aCompMgr) {
  1134.     return true;
  1135.   }
  1136. };
  1137.  
  1138. function NSGetModule(aCompMgr, aFile) {
  1139.   return Module;
  1140. }
  1141.